<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<title>进阶：16、Render函数 函数化组件</title>
	<script type="text/javascript" src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
	

	<script type="text/javascript">
		// ------------------------- 函数化组件 ---------------------------
		// 又来一个新概念，函数化组件是什么鬼啦？
		// 虽然后缀是组件，但实际上它只是一个函数，而且定义形式上更像组件，
		// 所以叫函数化组件，函数化组件并没有起到实际定义一个组件类型的作用
		// 更多时候它是一个函数，根据接收的数据props派发组件
		// 
		// 一个函数化组件的定义就像下面这样：
		// Vue.component('my-component', {
		//   // functional就是函数化的意思，创建一个函数化组件这里的声明必不可少
		//   functional: true,
		//   
		//   // 为了弥补缺少的实例
		//   // 提供第二个参数作为上下文
		//   // 真正派发组件的地方，根据props的数据派发组件
		//   render: function (createElement, context) {
		//     // ...
		//   },
		//   
		//   // Props 可选
		//   // 实际上你可以把它看成传递给这个函数化组件的数据参数啦！
		//   props: {
		//     // ...
		//   }
		// })
		// 
		// 组件需要的一切都是通过上下文传递，包括：
		// props: 提供props 的对象
		// children: VNode 子节点的数组
		// slots: slots 对象
		// data: 传递给组件的 data 对象
		// parent: 对父组件的引用
		// 
		// 这些东西都通过render的context参数来获取
		// this.$slots.default 更新为 context.children，之后this.level 更新为 context.props.level。
		// 
		// 因为函数化组件只是一个函数，所以渲染开销也低很多。在作为包装组件时它们也同样非常有用，比如，当你需要做这些时：
		// （1）程序化地在多个组件中选择一个
		// （2）在将 children, props, data 传递给子组件之前操作它们。
		// 下面是一个依赖传入 props 的值的 smart-list 组件例子，它能代表更多具体的组件：
		var EmptyList = { /* ... */ }
		var TableList = { /* ... */ }
		var OrderedList = { /* ... */ }
		var UnorderedList = { /* ... */ }

		Vue.component('smart-list',{
			functional: true,
			render: function(createElement, context){
				function appropriateListComponent(){
					var items = context.props.items

					if(items.length == 0)			 return EmptyList
					if(typeof items[0] === 'object') return TableList
					if(context.props.isOrdered)		 return OrderedList

					return UnorderedList
				}

				return createElement(
					appropriateListComponent(),
					context.data,
					context.children
				)
			},
			props: {
				items: {
				  type: Array,
				  required: true
				},
				isOrdered: Boolean
			}			
		})

		
	</script>
</body>
</html>